using System;

namespace Behaviorize
{
	public abstract class Step
	{
		internal readonly object[] Arguments;
		public readonly ScenarioVersion ScenarioVersion; // public to enable unit testing
		internal MulticastDelegate StepDelegate { get; set; }
		internal OutcomeType Outcome { get; set; }
		internal int FailureIndex { get; set; }
		internal abstract string ClauseName { get; }

		internal void ExecuteStep()
		{
			StepDelegate.DynamicInvoke(Arguments);
		}

		public override int GetHashCode()
		{
			unchecked
			{
				int hash = StepDelegate.Method.Name.GetHashCode();

				foreach (object argument in Arguments)
				{
					hash = hash * 397 + argument.GetHashCode();
				}

				return hash;
			}
		}

		#region Constructors

		internal Step(ScenarioVersion containingScenarioVersion, MulticastDelegate action)
		{
			StepDelegate = action;
			ScenarioVersion = containingScenarioVersion;
			Arguments = new object[0];
		}

		internal Step(ScenarioVersion containingScenarioVersion, MulticastDelegate action, object arg1)
		{
			StepDelegate = action;
			ScenarioVersion = containingScenarioVersion;
			Arguments = new[] {arg1};
		}

		internal Step(ScenarioVersion containingScenarioVersion, MulticastDelegate action, object arg1, object arg2)
		{
			StepDelegate = action;
			ScenarioVersion = containingScenarioVersion;
			Arguments = new[] {arg1, arg2};
		}

		internal Step(ScenarioVersion containingScenarioVersion, MulticastDelegate action, object arg1, object arg2, object arg3)
		{
			StepDelegate = action;
			ScenarioVersion = containingScenarioVersion;
			Arguments = new[] {arg1, arg2, arg3};
		}

		internal Step(ScenarioVersion containingScenarioVersion, MulticastDelegate action, object arg1, object arg2, object arg3, object arg4)
		{
			StepDelegate = action;
			ScenarioVersion = containingScenarioVersion;
			Arguments = new[] {arg1, arg2, arg3, arg4};
		}

		#endregion
	}
}